#pragma once

#include <thrust/inner_product.h>

template <typename Container1,
          typename Container2,
          typename T>
struct InnerProduct
{
  Container1 A;
  Container2 B;
  T init;

  template <typename Range1, typename Range2>
  InnerProduct(const Range1& X, const Range2& Y, T init)
    : A(X.begin(), X.end()),
      B(Y.begin(), Y.end()),
      init(init)
  {}

  void operator()(void)
  {
    thrust::inner_product(A.begin(), A.end(), B.begin(), init);
  }
  
  void reset(void)
  {
    // nothing to do
  }
};

template <typename Container1,
          typename Container2,
          typename T,
          typename BinaryOperation1,
          typename BinaryOperation2>
struct InnerProductBinaryOp
{
  Container1 A;
  Container2 B;
  T init;
  BinaryOperation1 binary_op1;
  BinaryOperation2 binary_op2;

  template <typename Range1, typename Range2>
  InnerProductBinaryOp(const Range1& X, const Range2& Y, T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2)
    : A(X.begin(), X.end()),
      B(Y.begin(), Y.end()),
      init(init),
      binary_op1(binary_op1),
      binary_op2(binary_op2)
  {}

  void operator()(void)
  {
    thrust::inner_product(A.begin(), A.end(), B.begin(), init, binary_op1, binary_op2);
  }
  
  void reset(void)
  {
    // nothing to do
  }
};

